﻿using System;
using System.Diagnostics;
using Microsoft.Practices.Unity.InterceptionExtension;

using SharedGenomics.Workbench.Core;

namespace SharedGenomics.Workbench.Aspects
{
    public class LoginRequiredCallHandler : ICallHandler
    {
        public LoginRequiredCallHandler(ILoginManager loginManager, ILoginPrompt loginPrompt)
        {
            this.LoginManager = loginManager;
            this.LoginPrompt = loginPrompt;
        }

        public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
        {
            if (this.LoginManager.IsLoggedIn || this.LoginPrompt.Login())
            {
                return getNext().Invoke(input, getNext);
            }
            else
            {
                return this.GetDefaultMethodReturn(input);
            }
        }

        public int Order { get; set; }

        private IMethodReturn GetDefaultMethodReturn(IMethodInvocation input)
        {
            Debug.Assert(input != null);

            Type returnType = this.GetMethodReturnType(input);

            if (returnType == typeof(void))
            {
                return input.CreateMethodReturn(null);
            }
            else
            {
                //method should be Maybe<T> which should also have a default constructor (which corresponds to nothing)
                Debug.Assert(returnType.IsGenericType);
                Debug.Assert(returnType.GetGenericTypeDefinition() == typeof(Maybe<>));

                object nothing = Activator.CreateInstance(returnType);
                return input.CreateMethodReturn(nothing);
            }
        }

        private Type GetMethodReturnType(IMethodInvocation input)
        {
            Debug.Assert(input != null);

            //amazingly this seem to be the only way to get the target method return type...
            return ((System.Reflection.MethodInfo)input.MethodBase).ReturnType;
        }

        private ILoginManager LoginManager { get; set; }
        private ILoginPrompt LoginPrompt { get; set; }
    }
}
